﻿using System;
using System.Threading;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// 自旋等待器
    /// </summary>
    public class SpinWaiter
    {
        private const int _DEFAULT_ITERATIONS = 5;

        /// <summary>
        /// CPU自旋等待指定毫秒数
        /// </summary>
        /// <param name="milliseconds">毫秒数</param>
        /// <param name="iterations">Thread.SpinWait单元,小于等于0取默认值5</param>
        /// <returns>实际等待的毫秒数</returns>
        public static double SpinWaitMilliseconds(double milliseconds, int iterations = _DEFAULT_ITERATIONS)
        {
            var nanosecond100s = milliseconds * 10000;
            if (nanosecond100s <= 0.1D)
            {
                return 0;
            }

            if (iterations <= 0)
            {
                iterations = _DEFAULT_ITERATIONS;
            }

            long ticks1 = DateTime.Now.Ticks;
            long durationTicks;
            while (true)
            {
                durationTicks = DateTime.Now.Ticks - ticks1;
                if (durationTicks > nanosecond100s)
                {
                    break;
                }
                else
                {
                    Thread.SpinWait(iterations);
                }
            }

            return ((double)durationTicks) / 10000;
        }


        /// <summary>
        /// CPU自旋等待指定100纳秒数
        /// </summary>
        /// <param name="nanosecond100s">自旋等待100纳秒数</param>
        /// <param name="iterations">Thread.SpinWait单元,小于等于0取默认值5</param>
        /// <returns>实际等待的100纳秒数</returns>
        public static double SpinWait100Nanoseconds(double nanosecond100s, int iterations = _DEFAULT_ITERATIONS)
        {
            if (iterations <= 0)
            {
                iterations = _DEFAULT_ITERATIONS;
            }

            long ticks1 = DateTime.Now.Ticks;
            long durationTicks;
            while (true)
            {
                durationTicks = DateTime.Now.Ticks - ticks1;
                if (durationTicks > nanosecond100s)
                {
                    break;
                }
                else
                {
                    Thread.SpinWait(iterations);
                }
            }

            return durationTicks;
        }

    }
}
